import { Sql, SQL_SYMBOLE } from '../sql';
import { XExpression, Expression } from './expression';
import { Func, BuiltIn, XObjectName, Star } from '../object';
import { BaseScalar, Scalar } from '../scalar';
import { Literal } from './literal';
import type { Sort } from '../statement';

/**
 * 函数调用表达式
 */
export class ScalarFuncInvoke<
  TReturn extends Scalar = any
> extends Expression<TReturn> {
  $func: Func<string>;
  $args: (Expression | BuiltIn | Star)[];
  readonly $type: SQL_SYMBOLE.SCALAR_FUNCTION_INVOKE =
    SQL_SYMBOLE.SCALAR_FUNCTION_INVOKE;

  $orders?: Sort[];
  $partitions?: Expression[];

  static isScalarFuncInvoke(object: any): object is ScalarFuncInvoke {
    return object?.$type === SQL_SYMBOLE.SCALAR_FUNCTION_INVOKE;
  }

  // TODO: 是否需参数的类型判断，拦截ValuedSelect之类的表达式进入？
  constructor(
    func: XObjectName | Func<string>,
    args: (XExpression<Scalar> | BuiltIn<string> | Star)[]
  ) {
    super();
    this.$func = Func.ensure(func);
    this.$args = args.map(expr => {
      if (!(expr instanceof Sql)) return new Literal(expr);
      return expr;
    });
  }

  over(
    action?: (
      builder: Pick<ScalarFuncInvoke, 'orderBy' | 'partitionBy'>
    ) => void
  ): this {
    action?.(this);
    return this;
  }

  /**
   * 开窗函数调用
   */
  orderBy(...sorts: Sort[]): this;
  orderBy(sorts: Sort[]): this;
  orderBy(...sorts: Sort[] | [Sort[]]): this {
    this.$orders = Array.isArray(sorts[0]) ? sorts[0] : (sorts as Sort[]);
    return this;
  }

  /**
   * 分组
   */
  partitionBy(exprs: XExpression<BaseScalar>[]): this;
  partitionBy(...exprs: XExpression<BaseScalar>[]): this;
  partitionBy(
    ...exprs: XExpression<BaseScalar>[] | [XExpression<BaseScalar>[]]
  ): this {
    const items: XExpression<BaseScalar>[] = (
      Array.isArray(exprs[0]) ? exprs[0] : exprs
    ) as XExpression<BaseScalar>[];
    this.$partitions = items.map(item => Expression.ensureExpression(item));
    return this;
  }
}
